﻿using System.ComponentModel;
using System.Windows;
using System.Windows.Media;
using Black.SurfaceToolkit.Tools;
using Microsoft.Surface.Presentation;
using Microsoft.Surface.Presentation.Controls;

namespace Black.SurfaceToolkit.Controls
{
    /// <summary>
    /// Contrôle d'expansion pour Surface.
    /// </summary>
    /// <remarks>
    /// <para>Ce contrôle permet l'ouverture et la fermeture d'un volet grâce à la propriété <see cref="P:Black.SurfaceToolkit.Controls.SurfaceExpander.IsExpanded" />.</para>
    /// <para>Lorsque <see cref="P:Black.SurfaceToolkit.Controls.SurfaceExpander.IsExpanded" /> est à <see langword="false" /> : le volet est fermé.</para>
    /// <para><div class="caption" style="font-weight : bold">Volet fermé</div></para>
    /// <para><img src="../Images/SurfaceExpander.Closed.png" /></para>
    /// <para>Lorsque <see cref="P:Black.SurfaceToolkit.Controls.SurfaceExpander.IsExpanded" /> est à <see langword="false" /> : le volet est ouvert.</para>
    /// <para><div class="caption" style="font-weight : bold">Volet ouvert</div></para>
    /// <para><img src="../Images/SurfaceExpander.Open.png" /></para>
    /// </remarks>
    [TemplatePart(Name = SurfaceExpander.MAIN_NAME, Type = typeof(FrameworkElement))]
    [TemplatePart(Name = SurfaceExpander.TOUCH_NAME, Type = typeof(FrameworkElement))]
    [Browsable(true), Description("Contrôle d'expansion")]
    public class SurfaceExpander : SurfaceContentControl
    {
        #region Constantes

        /// <summary>
        /// Nom du <see cref="T:System.Windows.FrameworkElement" /> principal.
        /// </summary>
        protected const string MAIN_NAME = "PART_cpMain";

        /// <summary>
        /// Nom du <see cref="T:System.Windows.FrameworkElement" /> définissant la zone de contact.
        /// </summary>
        protected const string TOUCH_NAME = "PART_ctlTouch";

        #endregion

        #region Propriétées de dépendances

        /// <summary>
        /// Clé la propriété de dépendance <see cref="P:Black.SurfaceToolkit.Controls.SurfaceExpander.VisibilityExpand" />.
        /// </summary>
        internal static readonly DependencyPropertyKey VisibilityExpandPropertyKey = DependencyProperty.RegisterReadOnly("VisibilityExpand", typeof(Visibility), typeof(SurfaceExpander), new UIPropertyMetadata(Visibility.Collapsed));

        /// <summary>
        /// Identifie la propriété de dépendance <see cref="P:Black.SurfaceToolkit.Controls.SurfaceExpander.Header" />.
        /// </summary>
        public static readonly DependencyProperty HeaderProperty = DependencyProperty.Register("Header", typeof(string), typeof(SurfaceExpander), new UIPropertyMetadata(null));
        /// <summary>
        /// Identifie la propriété de dépendance <see cref="P:Black.SurfaceToolkit.Controls.SurfaceExpander.HeaderBackground" />.
        /// </summary>
        public static readonly DependencyProperty HeaderBackgroundProperty = DependencyProperty.Register("HeaderBackground", typeof(Brush), typeof(SurfaceExpander), new UIPropertyMetadata(null));
        /// <summary>
        /// Identifie la propriété de dépendance <see cref="P:Black.SurfaceToolkit.Controls.SurfaceExpander.IsExpanded" />.
        /// </summary>
        public static readonly DependencyProperty IsExpandedProperty = DependencyProperty.Register("IsExpanded", typeof(bool), typeof(SurfaceExpander), new UIPropertyMetadata(BooleanBoxes.FalseBox, new PropertyChangedCallback(SurfaceExpander.OnIsExpandedChanged)));

        /// <summary>
        /// Identifie la propriété de dépendance <see cref="P:Black.SurfaceToolkit.Controls.SurfaceExpander.VisibilityExpand" />.
        /// </summary>
        internal static readonly DependencyProperty VisibilityExpandProperty = SurfaceExpander.VisibilityExpandPropertyKey.DependencyProperty;

        #endregion

        #region Accesseurs

        /// <summary>
        /// Obtient ou définit le titre.
        /// </summary>
        [Browsable(true), DefaultValue(null), Description("Titre"), Category("SurfaceExpander")]
        public string Header
        {
            get
            {
                return ((string)this.GetValue(SurfaceExpander.HeaderProperty));
            }
            set
            {
                this.SetValue(SurfaceExpander.HeaderProperty, value);
            }
        }

        /// <summary>
        /// Obtient ou définit le fond du titre.
        /// </summary>
        [Browsable(true), DefaultValue(null), Description("Fond du titre"), Category("SurfaceExpander")]
        public Brush HeaderBackground
        {
            get
            {
                return ((Brush)this.GetValue(SurfaceExpander.HeaderBackgroundProperty));
            }
            set
            {
                this.SetValue(SurfaceExpander.HeaderBackgroundProperty, value);
            }
        }

        /// <summary>
        /// Obtient ou définit une valeur indiquant si l'expander est ouvert.
        /// </summary>
        [Browsable(true), DefaultValue(false), Description("Valeur indiquant si l'expander est ouvert"), Category("SurfaceExpander")]
        public bool IsExpanded
        {
            get
            {
                return ((bool)this.GetValue(SurfaceExpander.IsExpandedProperty));
            }
            set
            {
                this.SetValue(SurfaceExpander.IsExpandedProperty, BooleanBoxes.Box(value));
            }
        }

        /// <summary>
        /// Obtient ou définit la visibilité de l'expand
        /// </summary>
        internal Visibility VisibilityExpand
        {
            get
            {
                return ((Visibility)this.GetValue(SurfaceExpander.VisibilityExpandProperty));
            }
            set
            {
                this.SetValue(SurfaceExpander.VisibilityExpandPropertyKey, value);
            }
        }

        #endregion

        #region Variables d'instance

        private FrameworkElement m_oTouchElement;
        private FrameworkElement m_oContentElement;

        #endregion

        #region Constructeurs

        /// <summary>
        /// Initialise la classe <see cref="T:Black.SurfaceToolkit.Controls.SurfaceExpander" />.
        /// </summary>
        static SurfaceExpander()
        {
            FrameworkElement.DefaultStyleKeyProperty.OverrideMetadata(typeof(SurfaceExpander), new FrameworkPropertyMetadata(typeof(SurfaceExpander)));
        }

        /// <summary>
        /// Initialise une nouvelle instance de <see cref="T:Black.SurfaceToolkit.Controls.SurfaceExpander" />.
        /// </summary>
        public SurfaceExpander()
            : base()
        {
        }

        #endregion

        #region Fonctions publiques

        /// <summary>
        /// Appelée pour appliquer le template.
        /// </summary>
        public override void OnApplyTemplate()
        {
            // Nettoyage du précédent template

            if (this.m_oTouchElement != null)
            {
                this.m_oTouchElement.RenderTransform = null;
                Contacts.RemoveContactTapGestureHandler(this.m_oTouchElement, new ContactEventHandler(this.ContactExpander));
            }

            // Traitement parent

            base.OnApplyTemplate();

            // Récupération des objets

            this.m_oContentElement = (FrameworkElement)this.Template.FindName(SurfaceExpander.MAIN_NAME, this);

            this.m_oTouchElement = (FrameworkElement)this.Template.FindName(SurfaceExpander.TOUCH_NAME, this);
            this.m_oTouchElement.RenderTransform = new RotateTransform(90);

            // Affectation des handler touch

            Contacts.AddContactTapGestureHandler(this.m_oTouchElement, new ContactEventHandler(this.ContactExpander));

            // On relance la vérification

            this.OnIsExpandedChanged(this.IsExpanded, this.IsExpanded);
        }

        #endregion

        #region Fonctions protégées

        /// <summary>
        /// Appelée lors d'un contact sur le <see cref="T:Black.SurfaceToolkit.Controls.SurfaceExpander" />.
        /// </summary>
        /// <param name="p_oArgs">Données de l'événement.</param>
        protected virtual void OnContactExpander(ContactEventArgs p_oArgs)
        {
        }

        /// <summary>
        /// Appelée lorsque la propriété <see cref="P:Black.SurfaceToolkit.Controls.SurfaceExpander.IsExpanded" /> est modifiée.
        /// </summary>
        /// <param name="p_bOldValue">Ancienne valeur.</param>
        /// <param name="p_bNewValue">Nouvelle valeur.</param>
        protected virtual void OnIsExpandedChanged(bool p_bOldValue, bool p_bNewValue)
        {
            // Vérification existance instance dans template

            if (this.m_oTouchElement == null)
                return;

            // Traitement valeur

            if (p_bNewValue)
            {
                this.VisibilityExpand = Visibility.Visible;
                (this.m_oTouchElement.RenderTransform as RotateTransform).Angle = 180;
            }
            else
            {
                this.VisibilityExpand = Visibility.Collapsed;
                (this.m_oTouchElement.RenderTransform as RotateTransform).Angle = 90;
            }
        }

        #endregion

        #region Fonctions privées

        /// <summary>
        /// Appelée lors d'un contact de l'expander.
        /// </summary>
        /// <param name="p_oSender">Source de l'événement.</param>
        /// <param name="p_oArgs">Données de l'événement.</param>
        private void ContactExpander(object p_oSender, ContactEventArgs p_oArgs)
        {
            // Invertion de la visibilité du contrôle

            this.IsExpanded = !this.IsExpanded;

            // Appel méthode virtuel

            this.OnContactExpander(p_oArgs);
        }

        #endregion

        #region Fonctions Statiques privées

        /// <summary>
        /// Appelée lorsque la propriété <see cref="P:Black.SurfaceToolkit.Controls.SurfaceExpander.IsExpanded" /> est modifiée.
        /// </summary>
        /// <param name="p_oSender">Source de l'événement.</param>
        /// <param name="p_oArgs">Données de l'événement.</param>
        private static void OnIsExpandedChanged(DependencyObject p_oSender, DependencyPropertyChangedEventArgs p_oArgs)
        {
            ((SurfaceExpander)p_oSender).OnIsExpandedChanged((bool)p_oArgs.OldValue, (bool)p_oArgs.NewValue);
        }

        #endregion
    }
}
